import React, { useEffect, useState, useRef } from 'react'
import styles from './index.module.less'
import G6 from './register'
import OPEN from './register/img/open.png'
import CLOSE from './register/img/close.png'
import GITLAB from './register/img/gitlab.jpg'
import JENKINS from './register/img/jenkins.jpg'
import DOCKER from './register/img/docker.jpg'
import NEXUS from './register/img/nexus.jpg'
import classNames from 'classnames'

const fittingString = (str, maxWidth, fontSize) => {
	const ellipsis = '...'
	const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0]
	let currentWidth = 0
	let res = str
	const pattern = new RegExp('[\u4E00-\u9FA5]+') // distinguish the Chinese charactors and letters
	str.split('').forEach((letter, i) => {
		if (currentWidth > maxWidth - ellipsisLength) return
		if (pattern.test(letter)) {
			// Chinese charactors
			currentWidth += fontSize
		} else {
			// get the width of single letter according to the fontSize
			currentWidth += G6.Util.getLetterWidth(letter, fontSize)
		}
		if (currentWidth > maxWidth - ellipsisLength) {
			res = `${str.substr(0, i)}${ellipsis}`
		}
	})
	return res
}

const globalFontSize = 12

const Test = () => {
	const inputEditRef = useRef()

	const [graph, setGraph] = useState(null) // 设置画布
	const [editFlag, setEditFlag] = useState(false)
	const [editValue, setEditValue] = useState('')
	const [targetId, setTargetId] = useState(null)

	const textShow = () => {
		setEditFlag(!editFlag)
	}

	const textChange = (event) => {
		const val = event.target.value
		setEditValue(val)
	}

	// 根据官网例子的接口获取的数据
	const initData = {
		nodes: [
			{
				id: 'node1',
				x: 10,
				y: 10,
				type: 'customNode',
				width: 100,
				firstText: '第一行文字第一行文字',
				secondText: '第二行文字第二行文字',
				thirdText: '第三行文字第三行文字',
			},
			{
				id: 'react',
				x: 120,
				y: 130,
				stroke: '#000',
				fill: '#66b2ff',
				type: 'diamond',
				label: 'React',
				anchorPoints: [
					[0.5, 0],
					[0.5, 1],
					[0, 0.5],
					[1, 0.5],
				],
				labelCfg: {
					style: {
						fill: '#000',
					},
				},
				size: [180, 60],
			},
			{
				id: 'docker',
				x: 120,
				y: 250,
				stroke: '#000',
				fill: 'transparent',
				radius: 6,
				type: 'card',
				label: '应用容器引擎',
				labelCfg: {
					style: {
						fill: '#000',
						fontSize: 16,
					},
				},
				iconCfg: {
					width: 80,
					height: 60,
				},
				size: [220, 100],
				img: DOCKER,
				anchorPoints: [
					[0.5, 0],
					[0.5, 1],
					[0, 0.5],
					[1, 0.5],
				],
			},
			{
				id: 'gitlab',
				x: 120,
				y: 500,
				stroke: '#000',
				fill: 'transparent',
				radius: 6,
				type: 'card',
				label: '代码仓库',
				labelCfg: {
					style: {
						fill: '#000',
						fontSize: 16,
					},
				},
				iconCfg: {
					width: 48,
					height: 48,
				},
				size: [180, 80],
				img: GITLAB,
				anchorPoints: [
					[0.5, 0],
					[0.5, 1],
					[0, 0.5],
					[1, 0.5],
				],
			},
			{
				id: 'jenkins',
				x: 120,
				y: 650,
				stroke: '#000',
				fill: '#fff',
				radius: 6,
				type: 'card',
				label: '构建工具',
				labelCfg: {
					style: {
						fill: '#000',
						fontSize: 16,
					},
				},
				iconCfg: {
					width: 120,
					height: 80,
				},
				anchorPoints: [
					[0.5, 0],
					[0.5, 1],
					[0, 0.5],
					[1, 0.5],
				],
				size: [220, 100],
				img: JENKINS,
			},
			{
				id: 'nexus',
				x: 500,
				y: 600,
				stroke: '#000',
				fill: '#fff',
				radius: 6,
				type: 'card',
				label: '镜像仓库',
				labelCfg: {
					style: {
						fill: '#000',
						fontSize: 16,
					},
				},
				iconCfg: {
					width: 120,
					height: 80,
				},
				anchorPoints: [
					[0.5, 0],
					[0.5, 1],
					[0, 0.5],
					[1, 0.5],
				],
				size: [220, 100],
				img: NEXUS,
			},
			{
				id: 'customEdit',
				x: 400,
				y: 350,
				stroke: '#000',
				fill: 'transparent',
				radius: 6,
				type: 'rect',
				label: '文本输入',
				labelCfg: {
					style: {
						fill: '#000',
						fontSize: 14,
					},
				},
				iconCfg: {
					width: 120,
					height: 80,
				},
				size: [100, 40],
				anchorPoints: [
					[0.5, 0],
					[0.5, 1],
					[0, 0.5],
					[1, 0.5],
				],
				img: NEXUS,
			},
			{
				id: 'docker2',
				x: 600,
				y: 350,
				stroke: '#000',
				fill: 'transparent',
				radius: 6,
				type: 'card',
				label: '应用容器引擎',
				labelCfg: {
					style: {
						fill: '#000',
						fontSize: 16,
					},
				},
				iconCfg: {
					width: 80,
					height: 60,
				},
				size: [220, 100],
				img: DOCKER,
				anchorPoints: [
					[0.5, 0],
					[0.5, 1],
					[0, 0.5],
					[1, 0.5],
				],
			},
		],
		edges: [
			{
				source: 'react',
				target: 'docker',
				type: 'line',
				label: '代码',
				// 该边连入 source 点的第 0 个 anchorPoint，
				sourceAnchor: 1,
				// 该边连入 target 点的第 0 个 anchorPoint，
				targetAnchor: 0,
				style: {
					endArrow: true,
					stroke: '#000',
				},
			},
			{
				source: 'docker',
				target: 'gitlab',
				type: 'customEdge',
				label: '自定义边可编辑备注',
				// 该边连入 source 点的第 0 个 anchorPoint，
				sourceAnchor: 1,
				// 该边连入 target 点的第 0 个 anchorPoint，
				targetAnchor: 0,
				style: {
					stroke: '#000',
					startArrow: {
						// 设置箭头路径
						path: 'M 0,0 L 10,5 L 10,-5 Z',
						fill: '#F6BD16',
						stroke: '#F6BD16',
					},
					endArrow: {
						path: 'M 0,0 L 10,5 L 10,-5 Z',
						fill: 'red',
						stroke: 'red',
					},
				},
			},
			{
				source: 'gitlab',
				target: 'jenkins',
				type: 'line',
				label: '拉取代码拉取代码',
				// 该边连入 source 点的第 0 个 anchorPoint，
				sourceAnchor: 1,
				// 该边连入 target 点的第 0 个 anchorPoint，
				targetAnchor: 0,
				style: {
					endArrow: true,
					stroke: '#000',
				},
			},
			{
				source: 'jenkins',
				target: 'nexus',
				type: 'quadratic',
				label: '构建镜像构建镜像',
				// 该边连入 source 点的第 0 个 anchorPoint，
				sourceAnchor: 3,
				// 该边连入 target 点的第 0 个 anchorPoint，
				targetAnchor: 4,
				style: {
					endArrow: true,
					stroke: '#000',
				},
			},
			{
				source: 'nexus',
				target: 'docker2',
				type: 'quadratic',
				label: '阿斯顿发',
				// 该边连入 source 点的第 0 个 anchorPoint，
				sourceAnchor: 0,
				// 该边连入 target 点的第 0 个 anchorPoint，
				targetAnchor: 1,
				style: {
					endArrow: true,
					stroke: '#000',
				},
			},
		],
	}

	const [data, setData] = useState(initData)

	data.nodes.forEach(function (node) {
		if (node.type === 'customNode') {
			node.firstText = fittingString(node.firstText, node.width, globalFontSize)
			node.secondText = fittingString(node.secondText, node.width, globalFontSize)
			node.thirdText = fittingString(node.thirdText, node.width, globalFontSize)
		}
	})

	// 初始化画布
	const setGraphObj = () => {
		const graph = new G6.Graph({
			container: 'container',
			width: 1500,
			height: 800,
			modes: {
				default: ['drag-node'],
			},
			defaultNode: {
				style: {
					fill: '#DEE9FF',
					stroke: '#5B8FF9',
				},
				linkPoints: {
					left: true,
					right: true,
					fill: '#fff',
					stroke: '#1890FF',
					size: 3,
				},
			},
			nodeStateStyles: {
				unselected: {
					openIcon: {
						img: OPEN,
					},
					text1: {
						stroke: 'blue',
					},
					text2: {
						stroke: 'blue',
					},
					text3: {
						stroke: 'transparent',
					},
					rect: {
						stroke: 'blue',
						height: 40,
					},
				},
				selected: {
					rect: {
						stroke: 'red',
						height: 80,
					},
					openIcon: {
						img: CLOSE,
					},
					text1: {
						stroke: 'red',
					},
					text2: {
						stroke: 'green',
					},
					text3: {
						stroke: 'gray',
					},
				},
			},
			edgeStateStyles: {},
		})

		graph.on('node:drag', (event) => {
			const item = event.item
			const model = item.getModel()
			item.toFront()
		})

		graph.on('node:click', (event) => {
			const item = event.item
			const model = item.getModel()

			if (model.id === 'node1') {
				const { states } = item._cfg
				if (states.includes('selected')) {
					graph.setItemState(item, 'selected', false)
					graph.setItemState(item, 'unselected', true)
				} else {
					graph.setItemState(item, 'selected', true)
					graph.setItemState(item, 'unselected', false)
				}
				return
			}

			if (model.type === 'card') {
				return
			}

			textShow()
			setTargetId(model.id)
			initEdit(model, 'node')
		})

		graph.on('edge:click', (event) => {
			textShow()
			const item = event.item
			const model = item.getModel()
			setTargetId(model.id)
			initEdit(item, 'edge')
			if (model.type === 'customEdge') {
				graph.updateItem(item, {
					style: {
						stroke: 'blue',
					},
				})
			}
		})

		graph.on('edge:mouseenter', (event) => {
			const item = event.item
			const model = item.getModel()

			if (model.type === 'customEdge') {
				graph.updateItem(item, {
					style: {
						stroke: 'red',
					},
				})
			}
		})

		graph.on('edge:mouseleave', (event) => {
			const item = event.item
			const model = item.getModel()

			if (model.type === 'customEdge') {
				graph.updateItem(item, {
					style: {
						stroke: '#000',
					},
				})
			}
		})

		setGraph(graph)
	}

	const initEdit = (target, type) => {
		const edit = inputEditRef.current

		setEditValue(() => '')
		edit.value = ''
		if (type === 'node') {
			edit.style.left = `${target.x - target.size[0] / 2}px`
			edit.style.top = `${target.y - target.size[1] / 2}px`
			edit.style.width = `${target.size[0]}px`
			edit.style.height = `${target.size[1]}px`
			edit.style.background = `#c6e5ff`
		}
		if (type === 'edge') {
			const t = target.get('originStyle')
			const textShape = t['text-shape']
			if (!textShape) {
				return
			}
			const { x, y } = textShape
			edit.style.left = `${x - 60}px`
			edit.style.top = `${y - 12}px`
			edit.style.width = `120px`
			edit.style.height = `24px`
			edit.style.borderBottom = '1px solid #efefef'
			edit.style.fontSize = `12px`
			edit.style.background = `#FFF`
		}
		edit.focus()
	}

	useEffect(() => {
		setGraphObj() // 初始化画布
	}, [])

	useEffect(() => {
		if (graph && data) {
			renderGraph() // 渲染画布
		}
	}, [data, graph])

	const renderGraph = () => {
		graph.clear() // 清除画布
		graph.data(data) // 传递数据
		graph.render() // 渲染画布
	}

	useEffect(() => {
		if (!editFlag && targetId) {
			const item = graph.findById(targetId)
			if (editValue) {
				graph.updateItem(
					item,
					{
						label: editValue,
					},
					true
				)
				setData(() => data)
			}
		}
	}, [editFlag, targetId, editValue])

	return (
		<div className={styles.testBox} id={'container'}>
			<input
				type="text"
				ref={inputEditRef}
				className={classNames(styles.inputEdit, !editFlag && styles.inputEditHidden)}
				onChange={textChange}
				onBlur={textShow}
			/>
		</div>
	)
}

export default Test
